/**
 *    
 */
package cn.springsoter.core.tool.utils;

import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.LongStream;

import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;

import com.google.common.collect.Lists;

import lombok.extern.slf4j.Slf4j;

/**
 * 日期工具类, 继承org.apache.commons.lang.time.DateUtils类
 * 
 * 更多Pattern请参考：cn.hutool.core.date.DatePattern
 * 
 * @author Kevin
 */
@Slf4j
public class DateUtil extends DateUtils {
	/**
	 * "yyyyMMddHHmmss"格式
	 */
	public static final String FULL_TIME_PATTERN = "yyyyMMddHHmmss";
	/**
	 * "yyyy-MM-dd HH:mm:ss"格式
	 */
	public static final String FULL_TIME_SPLIT_PATTERN = "yyyy-MM-dd HH:mm:ss";
	
	private static String[] parsePatterns = { "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm:ss.SSS",
			"yyyy-MM-dd HH:mm", "yyyy-MM", "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
			"yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM", "yyyy-MM-dd'T'HH:mm:ss'Z'",
			"yyyy-MM-dd'TZ'", "yyyy-MM-dd'T'HH:mm:ssXXX", "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", "yyyy-MM-dd'T'HH:mm:ss.SSSZ",
			"yyyy-MM-dd'T'HH:mm:ss.SSSXXX", "yyyy-MM-dd'T'HH:mm:ssZ", "EEE MMM dd HH:mm:ss zzz yyyy", "EEE, dd MMM yyyy HH:mm:ss z",
			"yyyyMMddHHmmssSSS", "yyyyMMddHHmmss", "HHmmss"};

	private DateUtil() {
	}
	
	/**
	 * 将LocalDateTime格式化为："yyyyMMddHHmmss"
	 * 
	 * @param localDateTime
	 * @return
	 */
	public static String formatFullTime(LocalDateTime localDateTime) {
		return formatFullTime(localDateTime, FULL_TIME_PATTERN);
	}

	/**
	 * 将LocalDateTime格式化为指定的 @param pattern
	 * 
	 * @param localDateTime
	 * @param pattern	指定格式化字符串
	 * @return
	 */
	public static String formatFullTime(LocalDateTime localDateTime, String pattern) {
		DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
		return localDateTime.format(dateTimeFormatter);
	}

	/**
	 * 获取指定日期的星期：周日：1，周一：2，以此类推，周六：7
	 * 
	 * @param date
	 * @return	int类型星期：周日 -> 1，周一 -> 2，以此类推，周六 -> 7
	 */
	public static int getDayOfWeek(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		return calendar.get(Calendar.DAY_OF_WEEK);
	}

	/**
	 * 获取今天从0点到当前时间的所有小时数
	 * 
	 * @return	所有小时List
	 */
	public static List<Integer> getTodayHoursBetween() {
		String str = LocalDate.now() + " 00:00:00";
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
		LocalDateTime stime = LocalDateTime.parse(str, formatter);
		LocalDateTime eTime = LocalDateTime.now();
		long hours = ChronoUnit.HOURS.between(stime, eTime);
		return IntStream.range(0, Long.valueOf(hours + 1).intValue()).boxed().collect(Collectors.toList());
	}

	/**
	 * 获取两个时间范围内的所有小时数
	 * 
	 * @param startTime	开始时间（LocalDateTime类型）
	 * @param endTime	结束时间（LocalDateTime类型）
	 * @return	所有小时List
	 */
	public static List<Long> getHoursBetween(LocalDateTime startTime, LocalDateTime endTime) {
		long hours = ChronoUnit.HOURS.between(startTime, endTime);
		return LongStream.range(0, hours + 1).boxed().collect(Collectors.toList());
	}

	/**
	 * 获取date后一天的日期
	 * 
	 * @param date	指定日期
	 * @return	Date
	 */
	public static Date getTomorrow(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.add(Calendar.DAY_OF_MONTH, 1);
		date = calendar.getTime();
		return date;
	}

	/**
	 * 获取date前一天的日期
	 * 
	 * @param date	指定日期
	 * @return	Date
	 */
	public static Date getYesterday(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.add(Calendar.DAY_OF_MONTH, -1);
		date = calendar.getTime();
		return date;
	}

	/**
	 * 获取date的上个月的日期
	 * 
	 * @param date	指定日期
	 * @return	Date
	 */
	public static Date getLastMonthDate(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.add(Calendar.MONTH, -1);
		date = calendar.getTime();
		return date;
	}

	/**
	 * 获取date前preIndex个月的日期
	 * 
	 * @param date	日期
	 * @param preIndex	前几个
	 * @return	Date
	 */
	public static Date getPreMonthDate(Date date, int preIndex) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.add(Calendar.MONTH, -preIndex);
		date = calendar.getTime();
		return date;
	}

	/**
	 * 获取preIndex天之前的日期，包含当天
	 * 
	 * @param date	日期
	 * @param preIndex	前几个
	 * @return	Date
	 */
	public static Date getPreDayDate(Date date, int preIndex) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.add(Calendar.DAY_OF_MONTH, -preIndex + 1);
		date = calendar.getTime();
		return date;
	}

	/**
	 * 格式化当前日期为：yyyy-MM-dd
	 * 
	 * @return	格式为：yyyy-MM-dd的字符串
	 */
	public static String getDate() {
		return getDate("yyyy-MM-dd");
	}

	/**
	 * 获取今天的UTC时间
	 * 
	 * @return 格式为：yyyy-MM-dd的字符串
	 */
	public static String getDateOfUTC() {
		System.setProperty("user.timezone", "UTC");
		TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
		Date date = new Date();
		return DateFormatUtils.format(date, "yyyy-MM-dd");
	}

	/**
	 * 格式化UTC时间为：yyyy-MM-dd'TZ' 字符串
	 * 
	 * @param tempDate
	 * @return	String
	 */
	public static String stringUTCFromDate(Date tempDate) {
		DateFormat format = new SimpleDateFormat("yyyy-MM-dd'TZ'");
		String dateText = format.format(tempDate);
		return dateText;
	}

	/**
	 * 格式化UTC时间为：yyyy-MM-dd'T'HH:mm:ss'Z' 字符串
	 * 
	 * @param tempDate
	 * @return	String
	 */
	public static String timeStringUTCFromDate(Date tempDate) {
		DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
		String dateText = format.format(tempDate);
		return dateText;
	}

	/**
	 * 格式化字符串：yyyy-MM-dd'T'HH:mm:ss'Z' 为日期对象
	 * 
	 * @param str	格式为：yyyy-MM-dd'T'HH:mm:ss'Z'的字符串
	 * @return	Date
	 */
	public static Date stringUTC2Date(String str) {
		DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
		Date date = null;
		try {
			date = format.parse(str);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		/*
		 * Calendar cal = Calendar.getInstance(); cal.setTime(date);
		 * cal.add(Calendar.HOUR, 8);// 24小时制, 比UTC时间延后8个小时 date = cal.getTime();
		 */
		return date;
	}

	/**
	 * 格式化字符串：yyyy-MM-dd'TZ' 为日期对象
	 * 
	 * @param str	格式为：yyyy-MM-dd'TZ'的字符串
	 * @return	Date
	 */
	public static Date string2UTCDate(String str) {
		DateFormat format = new SimpleDateFormat("yyyy-MM-dd'TZ'");
		Date date = null;
		try {
			date = format.parse(str);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return date;
	}

	/**
	 * 格式化字符串：yyyy-MM-dd HH:mm:ss 为日期对象
	 * 
	 * @param str	格式为：yyyy-MM-dd HH:mm:ss的字符串
	 * @return	Date
	 */
	public static Date fullTimeString2Date(String str) {
		DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Date date = null;
		try {
			date = format.parse(str);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return date;
	}

	/**
	 * 格式化字符串：yyyy-MM-dd 为日期对象
	 * 
	 * @param str	格式为：yyyy-MM-dd的字符串
	 * @return	Date
	 */
	public static Date string2Date(String str) {
		DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
		Date date = null;
		try {
			date = format.parse(str);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		/*
		 * Calendar cal = Calendar.getInstance(); cal.setTime(date);
		 * cal.add(Calendar.HOUR, 8);// 24小时制, 比UTC时间延后8个小时 date = cal.getTime();
		 */
		return date;
	}

	/**
	 * 得到当前日期指定pattern格式的字符串
	 * 
	 * @param pattern	可以为："yyyy-MM-dd"，"HH:mm:ss"，"E"等
	 * @return	指定pattern格式的字符串
	 */
	public static String getDate(String pattern) {
		return DateFormatUtils.format(new Date(), pattern);
	}

	/**
	 * 得到指定日期，指定pattern格式的字符串
	 * 
	 * @param pattern	可以为："yyyy-MM-dd"，"HH:mm:ss"，"E"等
	 * @return	指定pattern格式的字符串
	 */
	public static String formatDate(Date date, String pattern) {
		return DateFormatUtils.format(date, pattern);
	}

	/**
	 * 得到日期时间字符串，转换格式（yyyy-MM-dd HH:mm:ss）
	 */
	public static String formatDateTime(Date date) {
		return formatDate(date, "yyyy-MM-dd HH:mm:ss");
	}

	/**
	 * 得到当前时间字符串 格式（HH:mm:ss）
	 */
	public static String getTime() {
		return formatDate(new Date(), "HH:mm:ss");
	}

	/**
	 * 得到当前日期和时间字符串 格式（yyyy-MM-dd HH:mm:ss）
	 */
	public static String getDateTime() {
		return formatDate(new Date(), "yyyy-MM-dd HH:mm:ss");
	}

	/**
	 * 获取订单号
	 * 
	 * @param date	日期
	 * @return	订单号
	 */
	public static String getBillId(Date date) {
		String randomId = "" + (int) ((Math.random() * 9 + 1) * 10000);
		Date nowDate = new Date();
		return formatDate(date, "yyyyMMdd") + formatDate(nowDate, "HHmmss") + randomId;
	}

	/**
	 * 获取年份
	 * 
	 * @return	"yyyy"格式年份，比如：2021，2022
	 */
	public static String getYear() {
		return formatDate(new Date(), "yyyy");
	}

	/**
	 * 获取月份
	 * 
	 * @return	"MM"格式月份，比如：01，02，09，10
	 */
	public static String getMonth() {
		return formatDate(new Date(), "MM");
	}

	/**
	 * 获取天
	 * 
	 * @return	"dd"格式天，比如：01，09，10
	 */
	public static String getDay() {
		return formatDate(new Date(), "dd");
	}

	/**
	 * 获取星期
	 * 
	 * @return	"E"格式的星期，比如：星期二，星期三，星期四
	 */
	public static String getWeek() {
		return formatDate(new Date(), "E");
	}

	/**
	 * 日期型字符串转化为日期 格式 {"yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd
	 * HH:mm:ss.SSS", "yyyy-MM-dd HH:mm", "yyyy-MM", "yyyy/MM/dd", "yyyy/MM/dd
	 * HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM", "yyyy.MM.dd", "yyyy.MM.dd
	 * HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM", "yyyy-MM-dd'T'HH:mm:ss'Z'",
	 * "yyyy-MM-dd'TZ'"}
	 */
	public static Date parseDate(Object value) {
		if (value == null) {
			return null;
		}
		if (value instanceof Date) { // 使用频率最高的，应优先处理
			return (Date) value;
		}

		if (value instanceof Calendar) {
			return ((Calendar) value).getTime();
		}

		long longValue = -1;

		if (value instanceof BigDecimal) {
			longValue = NumberUtil.longValue((BigDecimal) value);
			return new Date(longValue);
		}

		if (value instanceof Number) {
			longValue = ((Number) value).longValue();
			return new Date(longValue);
		}

		try {
			return parseDate(value.toString(), parsePatterns);
		} catch (ParseException e) {
			return null;
		}
	}

	/**
	 * 获取从date到今天的天数，不包含今天 比如：（参数）2021-09-01 ～ （今天）2021-09-18 输出：17
	 * 
	 * @param date
	 * @return
	 */
	public static long pastDays(Date date) {
		long t = new Date().getTime() - date.getTime();
		return t / (24 * 60 * 60 * 1000);
	}

	/**
	 * 获取过去的小时
	 * 
	 * @param date
	 * @return
	 */
	public static long pastHour(Date date) {
		long t = new Date().getTime() - date.getTime();
		return t / (60 * 60 * 1000);
	}

	/**
	 * 获取过去的分钟
	 * 
	 * @param date
	 * @return
	 */
	public static long pastMinutes(Date date) {
		long t = new Date().getTime() - date.getTime();
		return t / (60 * 1000);
	}

	/**
	 * 转换为时间（天,时:分:秒.毫秒）
	 * 
	 * @param timeMillis
	 * @return
	 */
	public static String formatDateTime(long timeMillis) {
		long day = timeMillis / (24 * 60 * 60 * 1000);
		long hour = (timeMillis / (60 * 60 * 1000) - day * 24);
		long min = ((timeMillis / (60 * 1000)) - day * 24 * 60 - hour * 60);
		long s = (timeMillis / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - min * 60);
		long sss = (timeMillis - day * 24 * 60 * 60 * 1000 - hour * 60 * 60 * 1000 - min * 60 * 1000 - s * 1000);
		return (day > 0 ? day + "d," : "") + hour + "h:" + min + "m:" + s + "s." + sss + "ms";
	}

	/**
	 * 获取两个日期之间的天数
	 * 
	 * @param before
	 * @param after
	 * @return
	 */
	public static double getDistanceOfTwoDate(Date before, Date after) {
		long beforeTime = before.getTime();
		long afterTime = after.getTime();
		return (afterTime - beforeTime) / (1000 * 60 * 60 * 24);
	}

	/**
	 * 比较startTime和endTime的大小，2个时间格式必须是以"yyyy-MM-dd"开头
	 * 
	 * @param startTime
	 * @param endTime
	 * @return 1是startTime > endTime; 0是startTime = endTime; -1是startTime < endTime
	 */
	public static int compareTwoDays(String startTime, String endTime) {
		String startText = startTime.substring(0, 10);
		String endText = endTime.substring(0, 10);
		return startText.compareTo(endText);
	}

	/**
	 * 用Java8的方式获取两个时间区间值
	 * 
	 * @param startDate
	 * @param endDate
	 * @return
	 */
	public static List<LocalDate> getDatesBetweenUsingJava8(LocalDate startDate, LocalDate endDate) {
//		Instant si = sDate.toInstant();
//		Instant ei = eDate.toInstant();
//        ZoneId zoneId = ZoneId.systemDefault();
//
//        // atZone()方法返回在指定时区从此Instant生成的ZonedDateTime。
//        LocalDate startDate = si.atZone(zoneId).toLocalDate();
//        LocalDate endDate = ei.atZone(zoneId).toLocalDate();
		//获取LocalDate
		//LocalDate date = LocalDate.of(2016, 11, 30);
		long numOfDaysBetween = ChronoUnit.DAYS.between(startDate, endDate);
		return IntStream.iterate(0, i -> i + 1).limit(numOfDaysBetween + 1).mapToObj(i -> startDate.plusDays(i))
				.collect(Collectors.toList());
	}

	/**
	 * List<LocalDate> -> List<Date>
	 * 
	 * @param localDates
	 * @return
	 */
	public static List<Date> localDateToDate(List<LocalDate> localDates) {
		List<Date> dates = Lists.newArrayList();
		ZoneId zoneId = ZoneId.systemDefault();
		for (LocalDate ld : localDates) {
			ZonedDateTime zdt = ld.atStartOfDay(zoneId);
			Date date = Date.from(zdt.toInstant());
			dates.add(date);
		}
		return dates;
	}

	/**
	 * 计算2个时间的秒数
	 * 
	 * @param startDate
	 * @param endDate
	 * @return
	 */
	public static long calcuteSecondBetweenTwoDate(Date startDate, Date endDate) {
		long temp = endDate.getTime() - startDate.getTime();
		if (temp < 0) {
			temp = 0;
		}
		return temp / 1000;
	}

	/**
	 * 获取time 当天起始其时间的Calendar
	 * 
	 * @param time
	 * @return
	 */
	public static Calendar getDate(Long time) {

		TimeZone timeZone = TimeZone.getTimeZone("Asia/Shanghai");
		Calendar date = Calendar.getInstance(timeZone);

		date.setTimeInMillis(time / (3600 * 24 * 1000) * (1000 * 3600 * 24));
		return date;
	}

	/**
	 * 获取当天的的起止时间(上海时区)
	 * 
	 * @return
	 */
	public static Map<String, Long> getBeginAndEnd(long timeStamp) {
		// typeCount 今日
		TimeZone timeZone = TimeZone.getTimeZone("Asia/Shanghai");
		Calendar date = Calendar.getInstance(timeZone);
		date.setTimeInMillis(timeStamp);
		date.set(Calendar.HOUR_OF_DAY, 0);
		date.set(Calendar.MINUTE, 0);
		date.set(Calendar.SECOND, 0);
		date.set(Calendar.MILLISECOND, 0);
		Long beiginTime = date.getTimeInMillis();// 获取当天的起始秒值.eg:2019-12-04 00:00:00 毫秒
		date.set(Calendar.DAY_OF_MONTH, -1);
		Long endTime = beiginTime + 3600 * 24 * 1000 - 1;// 获取当天的结束时间 eg：2019-12-04 23:59:59
		Map<String, Long> retMap = new HashMap<String, Long>();
		retMap.put("beginTime", beiginTime);
		retMap.put("endTime", endTime);
		return retMap;
	}

	/**
	 * 获取两个时间戳间的所有日期
	 * 
	 * @param begintime	开始时间戳
	 * @param endtime	结束时间戳
	 * @return
	 */
	public static List<String> getDays(Long begintime, Long endtime) {
		LinkedList<String> days = new LinkedList<>();
		Calendar beginDate = DateUtil.getDate(begintime);
		Calendar endDate = DateUtil.getDate(endtime);
		SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd");
		String date = dateformat.format(beginDate.getTime());
		do {
			days.add(date);
			beginDate.add(Calendar.DAY_OF_MONTH, 1);
			date = dateformat.format(beginDate.getTime());
		} while (beginDate.compareTo(endDate) <= 0);
		return days;
	}

	/**
	 * 获取两个时间戳间的天数
	 * 
	 * @param begintime	开始时间戳
	 * @param endtime	结束时间戳
	 * @return
	 */
	public static int getDaysBetweenTwoDateTime(Long begintime, Long endtime) {
		return getDays(begintime, endtime).size();
	}

	/**
	 * 采用LocalDate,计算出两个时间戳之间的所有日期
	 * 
	 * @param begintime	开始时间戳
	 * @param endtime	结束时间戳
	 * @return
	 */
	public static List<String> getDateListByLocalDate(Long startTime, Long endTime) {
		LocalDate begin = dateToLocalDate(new Date(startTime));
		LocalDate end = dateToLocalDate(new Date(endTime));
		List<String> resultList = Lists.newArrayList();
		long length = end.toEpochDay() - begin.toEpochDay();
		for (long idx = length; idx >= 0; idx--) {
			resultList.add(end.minusDays(idx).toString());
		}
		return resultList;
	}

	/**
	 * Date -> LocalDate
	 * 
	 * @param date
	 * @return
	 */
	public static LocalDate dateToLocalDate(Date date) {
		return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
	}

	/**
	 * 将秒数转换为日时分秒
	 *
	 * @param second 秒数
	 * @return 时间
	 */
	public static String secondToTime(Long second) {
		// 判断是否为空
		if (second == null || second == 0L) {
			return StringPool.EMPTY;
		}
		// 转换天数
		long days = second / 86400;
		// 剩余秒数
		second = second % 86400;
		// 转换小时
		long hours = second / 3600;
		// 剩余秒数
		second = second % 3600;
		// 转换分钟
		long minutes = second / 60;
		// 剩余秒数
		second = second % 60;
		if (days > 0) {
			return StringUtil.format("{}天{}小时{}分{}秒", days, hours, minutes, second);
		} else {
			return StringUtil.format("{}小时{}分{}秒", hours, minutes, second);
		}
	}

	/**
	 * 获取今天的日期
	 *
	 * @return 时间
	 */
	public static String today() {
		return formatDate(new Date(), "yyyyMMdd");
	}
}
